﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JWT;
using JWT.Algorithms;
using JWT.Exceptions;
using JWT.Serializers;
using WebApiTest.Dto.System;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Globalization;
using Newtonsoft.Json;

namespace WebApiTest.Dto.Utils
{
    public class JWTUtil
    {
        private ILogger<JWTUtil> _logger;

        public JWTUtil(ILogger<JWTUtil> logger)
        {
            _logger = logger;
        }

        private static string pubKey = "20010809";

        public static string DesEncrypt(string input)
        {
            var des = new DESCryptoServiceProvider();
            var bytes = Encoding.UTF8.GetBytes(input);
            des.Key = Encoding.ASCII.GetBytes(pubKey);
            des.IV = Encoding.ASCII.GetBytes(pubKey);
            using (var ms = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(bytes, 0, bytes.Length);
                    cryptoStream.FlushFinalBlock();
                }
                var data = ms.ToArray();
                return BitConverter.ToString(data).Replace("-", "");
            }
        }

        public static string DesDecrypt(string input)
        {
            var des = new DESCryptoServiceProvider();
            var bytes = Hex2Bytes(input);
            des.Key = Encoding.ASCII.GetBytes(pubKey);
            des.IV = Encoding.ASCII.GetBytes(pubKey);
            using (var ms = new MemoryStream())
            {
                using (var cryptoStream = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(bytes, 0, bytes.Length);
                    cryptoStream.FlushFinalBlock();
                }
                var data = ms.ToArray();
                return Encoding.UTF8.GetString(data);
            }
        }

        public static string CreatSign(string seed)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);

            var token = encoder.Encode(seed, pubKey);
            return token;
        }
         
        public static TokenDTO verifyToken(string token)
        {
            TokenDTO tokenDTO = new TokenDTO();
            try
            {
                // ijwtalgorithm algorithm = new hmacsha256algorithm();
                // ijsonserializer serializer = new jsonnetserializer();
                // idatetimeprovider provider = new utcdatetimeprovider();
                /// ijwtvalidator validator = new jwtvalidator(serializer, provider);
                // ibase64urlencoder urlencoder = new jwtbase64urlencoder();
                //IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
                string json = DesDecrypt(token);
                ///string json = decoder.Decode(token, pubKey, verify: true);
                JObject jObject = JObject.Parse(json);
                tokenDTO.accountId = (long)jObject["accountId"];
            }
            catch (Exception e)
            {
                Console.WriteLine("Token验证 ======> " + JsonConvert.SerializeObject(tokenDTO));
                Console.WriteLine(e.ToString());
                tokenDTO = null;
            }
            return tokenDTO;
        }


        /// <summary>
        /// 用指定公钥加密文本
        /// </summary>
        /// <param name="publicKey">公钥</param>
        /// <param name="input">文本</param>
        /// <returns></returns>
        public static string RsaEncrypt(string publicKey, string input)
        {
            const string sFormat =
                "<RSAKeyValue><Modulus>{0}</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
            var provider = new RSACryptoServiceProvider();
            var arrPubKey = Hex2Bytes(publicKey);
            var pkB64 = Convert.ToBase64String(arrPubKey);
            var xmlStr = string.Format(sFormat, pkB64);
            var bytesInput = Encoding.UTF8.GetBytes(input);
            provider.FromXmlString(xmlStr);
            var encryptArray = provider.Encrypt(bytesInput, false);
            var hexStr = BitConverter.ToString(encryptArray).Replace("-", "");
            return hexStr.ToLower();
        }


        /// <summary>
        /// 将字节转换成16进制数字
        /// </summary>
        /// <param name="bytes">字节数组</param>
        /// <returns></returns>
        public static string Bytes2Hex(byte[] bytes)
        {
            var buffer = new StringBuilder();
            foreach (var t in bytes)
            {
                buffer.AppendFormat("{0:x2}", t);
            }
            return buffer.ToString();
        }

        public static byte[] Hex2Bytes(string input)
        {
            if (string.IsNullOrEmpty(input)) return null;
            var offset = input.Length % 2;
            if (offset == 1) input = "0" + input;
            int i;
            var list = new List<byte>();
            for (i = 0; i < input.Length; i += 2)
            {
                var temp = input.Substring(i, 2);
                byte bv;
                var success = byte.TryParse(temp, NumberStyles.HexNumber, null, out bv);
                if (!success) throw new ArgumentOutOfRangeException();
                list.Add(bv);
            }
            return list.ToArray();
        }

        public static string MD5Encrypt(string str)
        {
            //utf8,x2:十六进制表示，占两位
            //创建对象方法：构造方法，静态方法(工厂模式)
            MD5 md5 = MD5.Create();
            //将字符串转换为字节数组
            byte[] byte0ld = Encoding.UTF8.GetBytes(str);
            //调用加密方法
            byte[] byteNew = md5.ComputeHash(byte0ld);
            //将加密结果进行转换成字符串
            StringBuilder sb = new StringBuilder();
            foreach (byte b in byteNew)
            {
                //将字符转换成十六进制表示的字符串，并且恒占用两位
                sb.Append(b.ToString("x2"));
            }
            //返回加密字符串
            return sb.ToString();
        }

    }
}